#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "xpower.h"

#define CMD_GET_ADC              0x01
#define CMD_SET_POWER_OFF        0x02

#define MAX_I2C_ARGC      7
#define SLA_ADDR         0xD0    //0x68 7bit-address

enum i2cs_state {
	WAIT_RECEIVE = 0,
	SLAVE_RECEIVING,

	WAIT_TRANSMIT,
	SLAVE_TRNSMITTING,
};

static UINT8 i2cs_argv[MAX_I2C_ARGC+1];
static UINT8 g_i2cs_state = WAIT_RECEIVE;
static UINT8 i2cs_argc = 0;

void reset_i2cs_state()
{
	i2cs_argc = 0;
	g_i2cs_state = WAIT_RECEIVE;
}

void do_cmd_get(void)
{
	UINT8 cmd = i2cs_argv[0];
    UINT8 adcrh = 0;
    UINT8 adcrl = 0;
    UINT16 vol = 0;
    UINT8 i = 3, first = 1; 

	//XXX:clear argc, recalc resend buf
	i2cs_argc = 0;

	switch (cmd) {
    	case CMD_GET_ADC: {
           do {
    		    clr_ADCF;
    		    set_ADCS;
    		    while(ADCF == 0);
                if (first) {
                    first = 0;
                    adcrh = ADCRH;
                    adcrl = ADCRL;
                } else {
                    adcrh = (adcrh + ADCRH) >> 1;
                    adcrl = (adcrl + ADCRL) >> 1;
                }
            } while(--i);
            vol = (adcrh << 4) | adcrl;
    		i2cs_argv[i2cs_argc++] = (vol >> 8);
    		i2cs_argv[i2cs_argc++] = (UINT8)vol;  //smbus lsb first
    		break;
        }
    	default:{
    		break;
        }
    }
	g_i2cs_state = WAIT_TRANSMIT;
}

void do_cmd_set(void)
{
	UINT8 cmd = i2cs_argv[0];

	switch (cmd) {
    	case CMD_SET_POWER_OFF: {
    		if (i2cs_argv[1]) {
    			set_ap_power_off();
    		} else {
    			set_ap_power_on();
    		}
    		break;
        }
    	default: {
    		break;
        }
    }

	reset_i2cs_state();
}

//return the received buf position
UINT8 on_received(void)
{
	if (g_i2cs_state != SLAVE_RECEIVING)
		g_i2cs_state = SLAVE_RECEIVING;

	i2cs_argv[i2cs_argc++] = I2DAT;
	return i2cs_argc;
}

//RECEIVED --> WAIT_TRANSMITTER --> TRANSMITTER
void on_stop_or_restart(void)
{
	switch (g_i2cs_state) {
    	case SLAVE_RECEIVING:
    	{
    		if (i2cs_argc == 1) { //read command
    			do_cmd_get();
    		} else {
    			do_cmd_set();
    		}
    
    		break;
    	}
    	case WAIT_TRANSMIT:
    	case SLAVE_TRNSMITTING:
    	{
    		i2cs_argc = 0;
    		g_i2cs_state = WAIT_RECEIVE;
    		break;
    	}
    }
}

UINT8 on_transmitter(void)
{
    //I2DAT = 0xcc;
	if (g_i2cs_state == WAIT_TRANSMIT)
		g_i2cs_state = SLAVE_TRNSMITTING;

	if ((g_i2cs_state == SLAVE_TRNSMITTING) &&
		(i2cs_argc > 0)) {
		I2DAT = i2cs_argv[--i2cs_argc];
	}

	return i2cs_argc;
}

void i2c_isr(void) interrupt 6
{
	UINT8 where = 0;

    switch (I2STAT)
    {
        case 0x00:
			set_STO;
            break;

        case 0x60:
			set_AA;
            break;

        case 0x80:
			where = on_received();

			if (where == MAX_I2C_ARGC) //will rx last data
				clr_AA;
            else
				set_AA;
            break;

        case 0x88:
			on_received();
			set_AA;
            break;

        case 0xA0:
			on_stop_or_restart();
			set_AA;
            break;

        case 0xA8:
			where = on_transmitter();
			if (where == 0) //last byte tobe transmit
				clr_AA;
			else
				set_AA;
            break;
        case 0xB8:
			where = on_transmitter();
			if (where == 0)
				clr_AA;
			else
				set_AA;
            break;

        case 0xC0:
			reset_i2cs_state();
			set_AA;
            break;

        case 0xC8:
			reset_i2cs_state();
			set_AA;
            break;
    }

    SI = 0;
    while(STO);
}

void init_adc(void)
{
	Enable_ADC_AIN5;
}

void init_i2cs(void)
{
    P13_Quasi_Mode;                         //set SCL (P13) is Quasi mode
    P14_Quasi_Mode;                         //set SDA (P14) is Quasi mode


    SDA = 1;                                //set SDA and SCL pins high
    SCL = 1;

    set_P1SR_3;                             //set SCL (P13) is  Schmitt triggered input select.
    //set_P1SR_4;

    set_EI2C;                               //enable I2C interrupt by setting IE1 bit 0

    I2ADDR = SLA_ADDR;                      //define own slave address
    set_I2CEN;                              //enable I2C circuit
    set_AA;

	init_adc();
}
